import logging

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.core.cache import cache
from wechatpy.client.api import WeChatWxa

from application import dispatch, settings
from application.dispatch import is_tenants_mode
from dvadmin_sms.utils import get_sms_code
from dvadmin_third.models import ThirdUsers
from .wechat import get_wechat_pool
from dvadmin.system.models import Users
from dvadmin.utils.request_util import get_request_ip, get_ip_analysis
from dvadmin.utils.validator import CustomValidationError

logger = logging.getLogger(__name__)
UserModel = get_user_model()


class UniAppWxCodeBackend(ModelBackend):
    """
    UniApp 微信小程序微信code 认证方式
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        """
        :param request:
        :param username:
        :param password:
        :param kwargs:
        :return:
        """
        if not hasattr(request, 'data'):
            return None
        app_id = request.data.get('app_id')
        if not app_id:
            return None
        mode = request.data.get('mode')
        phone_code = request.data.get('phone_code')
        if mode not in ['saas', 'standalone']:
            return None
        if not phone_code:
            return None
        code = password
        if len(code) != 32:
            return None
        if not is_tenants_mode():
            msg = '%s UniApp正在使用微信code登录...' % code
            logger.info(msg)
            # 单模式
            # 1. 通过配置，是否允许注册直接登录(只允许后台已添加用户进行登录)
            # 2. 通过手机号进行校验是否在后台存在账号
            app_secret = settings.WECHAT_APP_IDS.get(app_id, None)
            we_chat_wxa_obj = WeChatWxa(client=get_wechat_pool(app_id, app_secret))
            user_info = we_chat_wxa_obj.code_to_session(code)
            openid = user_info.get('openid', None)
            login_ip = get_request_ip(request)
            union_id = user_info.get('unionid', None)
            phone_info = we_chat_wxa_obj.get_phone_number(phone_code)
            phone = None
            if phone_info.get('errcode') == 0:
                phone = phone_info.get('phone_info', {}).get('purePhoneNumber')
            if openid:
                # 1.查找微信openid后，正常登录
                third_user = ThirdUsers.objects.filter(open_id=openid).first()
                if third_user and third_user.user:
                    return third_user.user
                # 2.如果不允许注册直接登录时，查找手机号是否存在
                user = Users.objects.filter(mobile=phone).first()
                # 是否允许注册直接登录
                direct_register_login = dispatch.get_system_config_values("uniapp.direct_register_login") or False
                if not direct_register_login and not user:
                    raise CustomValidationError(f"当前手机号未注册，请联系管理员!")
                if not user:
                    user = Users.objects.create(username=f"uniapp_openid", mobile=phone, user_type=1)
                    user.modifier = user.id
                    user.save()
                # 3. 校验是否有微信信息,不存在直接创建
                if not ThirdUsers.objects.filter(user=user).exists():
                    analysis = get_ip_analysis(ip=login_ip)
                    ThirdUsers.objects.create(**{
                        "user": user,
                        "open_id": openid,
                        "union_id": union_id,
                        "openname": user.name,
                        "login_ip": login_ip,
                        "latitude": analysis.get('latitude'),
                        "longitude": analysis.get('longitude'),
                        "country": analysis.get('country'),
                        "province": analysis.get('province'),
                        "city": analysis.get('city'),
                        "district": analysis.get('district'),
                        "avatar_url": user_info.get('headimgurl'),
                        "session_key": user_info.get('session_key', None),

                    })
                return user
        # TODO 多租户模式


class UniAppPhoneCodeBackend(ModelBackend):
    """
    UniApp 手机号登录 认证方式
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        """
        :param request:
        :param username:
        :param password:
        :param kwargs:
        :return:
        """
        if not hasattr(request, 'data'):
            return None
        app_id = request.data.get('app_id')
        if not app_id:
            return None
        mode = request.data.get('mode')
        login_type = request.data.get('login_type')
        if login_type != 'phone':
            return None
        code = password
        if len(code) != 6:
            return None
        msg = '%s UniApp正在使用手机号登录...' % username
        logger.info(msg)
        # 校验验证码
        cache_code = get_sms_code(username)
        if not cache_code:
            raise CustomValidationError('验证码已失效请重新获取!')
        if str(cache_code) != code:
            raise CustomValidationError('验证码错误!')
        user = Users.objects.filter(mobile=username).first()
        # 如果不允许注册直接登录时，无法登录
        direct_register_login = dispatch.get_system_config_values("uniapp.direct_register_login") or False
        if not direct_register_login and not user:
            raise CustomValidationError('当前手机号未注册，请联系管理员!')
        # 用户不存在则进行创建
        if not user:
            user = Users.objects.create(username=f'uniapp_{username}', mobile=username, user_type=1)
            user.modifier = user.id
            user.save()
        if not user.is_active:
            raise CustomValidationError('您已被禁用,请联系管理员!')
        if not ThirdUsers.objects.filter(user=user).first():
            raise CustomValidationError('请第一次使用微信登录!')
        cache.delete(f"uniapp_code_{username}")
        return user
